﻿using System;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;

namespace Infrastructure.Diagnostics
{
    public static class Logger
    {
        #region private properties

        private static ICollection<ILogListener> m_listeners = new List<ILogListener>();

        #endregion

        #region interface

        public static void AddListener(ILogListener listener)
        {
            lock (m_listeners) m_listeners.Add(listener);
        }

        public static void RemoveListener(ILogListener listener)
        {
            lock (m_listeners) m_listeners.Remove(listener);
        }

        public static void Debug(string format, params object[] args)
        {
            AddEntry(LogSeverity.Debug, format, args);
        }

        public static void Info(string format, params object[] args)
        {
            AddEntry(LogSeverity.Info, format, args);
        }

        public static void Warning(string format, params object[] args)
        {
            AddEntry(LogSeverity.Warning, format, args);
        }

        public static void Error(string format, params object[] args)
        {
            AddEntry(LogSeverity.Error, format, args);
        }

        #endregion

        #region private methods

        private static void AddEntry(LogSeverity severity, string format, params object[] args)
        {
            var logEntry = new LogEntry();

            logEntry.Message = string.Format(format, args);

            logEntry.OccuranceTime = DateTime.Now;

            logEntry.Severity = severity;

            logEntry.StackTrace = new StackTrace();

            logEntry.Caller = GetCaller(logEntry.StackTrace);

            NotifyListeners(logEntry);
        }

        private static MethodBase GetCaller(StackTrace stackTrace)
        {
            int i = 0;
            while (stackTrace.GetFrame(i).GetMethod().DeclaringType != typeof(Logger)) ++i;
            while (stackTrace.GetFrame(i).GetMethod().DeclaringType == typeof(Logger)) ++i;
            return stackTrace.GetFrame(i).GetMethod();
        }

        private static void NotifyListeners(ILogEntry entry)
        {
            lock (m_listeners)
            {
                foreach (var listener in m_listeners) listener.LogEntry(entry); 
            }
        }

        #endregion
    }
}
